
//
// 110521 - AH - (Opera) Created.
// 120117 - AH - (Huset) Counter property.
// 120220a- AH - (Aura) Renamed advanced() to painted().
// 120220b- AH - (Aura) Added ConversationEvent sequence property.
// 120224 - AH - (Kryddar *) Changes related to that the ScanPaintResult is
//               replaced by this: W, SW, LINES.
//

package org.soekrat.engine.motor;

import java.util.ArrayList;
import java.util.List;

import org.soekrat.AttributeObject;
import org.soekrat.engine.event.SoekratChangeEvent;
import org.soekrat.engine.event.SoekratChangeListener;
import org.soekrat.engine.visitor.Lines;
import org.soekrat.engine.wheel.ontology.Ontology;

/**
 * <p>
 *   {@link AttributeObject} in the use of being passed among objects involved
 *   in retrieval.
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC)
 */
public final class ConversationElement extends AttributeObject 
{
  /**
   * <p>
   *   The name on the attribute for {@code this} and 
   *   {@link ConversationEvent}s for what has for what has been painted. 
   * </p>
   */
  public static final String PAINT="paint";
  
  /**
   * <p>
   *   The name on the attribute for {@code this} for processed 'wheel'
   *   retrieved data to visitor.
   * </p>
   */
  public static final String W="w";
  
  /**
   * <p>
   *   The name on the attribute for {@code this} for processed 'spare wheel'
   *   retrieved data to visitor.
   * </p>
   */
  public static final String SW="sw";
  
  /**
   * <p>
   *   The name on the attribute for {@code this} for visitor input in form of
   *   {@link Lines} object.
   * </p>
   */
  public static final String LINES="lines";
  
  /**
   * <p>
   *   The name on the attribute for 
   *   {@link ConversationEvent}s for class on ontology that painted.
   * </p>
   */
  public static final String SOURCE_CLASS="source-class";
  
  /**
   * <p>
   *   The name on the attribute for 
   *   {@link ConversationEvent}s for name on ontology associated with event.
   * </p>
   */
  public static final String SOURCE_NAME="source";
  
  private transient List<SoekratChangeListener> m_listeners=null;
  
  private final List<ConversationEvent> m_events=
    new ArrayList<ConversationEvent>();
  
  private int m_counter=0;
  
  /**
   * <p>
   *   Constructor.
   * </p>
   */
  public ConversationElement(){}
  
  /**
   * <p>
   *   Advances counter.
   * </p>
   * @param source {@link Ontology} that painted.
   */
  public void painted(Ontology source)
  { 
    if (source==null)
    {
      throw new NullPointerException("source");  
    }
    
    m_counter++; 
    ConversationEvent e=createEvent("Painted");
    
    @SuppressWarnings("unchecked")
    List<AttributeObject> paint=(List<AttributeObject>)getAttribute(PAINT);
    
    if (paint!=null) e.setAttribute(PAINT, paint);
    
    setAttribute(SOURCE_CLASS, source.getClass());
    
    e.setAttribute(SOURCE_NAME, source.getName());
    
    fire();
  }
  
  // UGLY, goes away when all done by passing strategy.
  public void setPainted(List<AttributeObject> wp, List<AttributeObject> swp)
  {
    setAttribute(ConversationElement.W, wp);
    setAttribute(ConversationElement.SW, swp);
    
    if (!swp.isEmpty())
    {
      ConversationEvent e=createEvent("Sparewheel Painted");
      e.setAttribute(PAINT, swp);
      fire();
    }
  }
  
  /**
   * <p>
   *   Makes ready to be painted by result from new visitor input..
   * </p>
   * @param lines {@link Lines} which is visitor input.
   */
  public void turnTaking(Lines lines)
  {
    clearAttributes();
    
    setAttribute(LINES, lines);
    
    createEvent("Turn Taking");
    
    fire();
  }
  
  /**
   * <p>
   *   Gets counter valuse.
   * </p>
   * @return Value.
   */
  public int getCounter(){ return m_counter; }
  
  /**
   * <p>
   *   Creates a
   *   {@link ConversationEvent} to be associated with {@code this} one's
   *   life.
   * </p>
   * @param desc Event description.
   * @return Created.
   */
  public ConversationEvent createEvent(String desc)
  {
    ConversationEvent retVal=new ConversationEvent(desc);
    m_events.add(retVal);
    return retVal;
  }
  
  /**
   * <p>
   *   Gets number of
   *   {@link ConversationEvent}s {@code this} have.
   * </p>
   * @return Count.
   */
  public int getEventCount(){ return m_events.size(); }
  
  /**
   * <p>
   *   Gets
   *   {@link ConversationEvent}.
   * </p>
   * @param idx Index of even to get.
   * @return {@code ConversationEvent}.
   * @throws IndexOutOfBoundsException If {@code idx<0 || idx>=getEventCount()}.
   */
  public ConversationEvent getConversationEvent(int idx)
  { 
    return m_events.get(idx); 
  }
  
  /**
   * <p>
   *   Adds 
   *   {@link SoekratChangeListener}.
   * </p>
   * @param l Listener to add.
   */
  public synchronized void addSoekratChangeListener(SoekratChangeListener l)
  {
    if (l==null)
    {
      throw new NullPointerException("l");
    }
    
    if (m_listeners==null) m_listeners=new ArrayList<SoekratChangeListener>();
    if (!m_listeners.contains(l)) m_listeners.add(l);
  }
  
  /**
   * <p>
   *   Removes. 
   *   {@link SoekratChangeListener}.
   * </p>
   * @param l Listener to remove.
   */
  public synchronized void removeSoekratChangeListener(SoekratChangeListener l)
  {
    if (l==null)
    {
      throw new NullPointerException("l");
    }
    
    if (m_listeners==null) return;
    m_listeners.remove(l);
  }
  
  private final SoekratChangeEvent m_event=new SoekratChangeEvent(this);
  
  // Fires change 
  private void fire()
  {
    if (m_listeners==null) return;
    
    SoekratChangeListener[] l=SoekratChangeListener.E_ARRAY;
    synchronized(this){ l=m_listeners.toArray(l); }
    
    for (SoekratChangeListener curr : l) curr.changed(m_event);
  }
  
}
